home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / Level 0 Macintosh 07Aug94 / Files.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  24.7 KB  |  816 lines  |  [TEXT/KAHL]

  1. /* Files.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Debug.h"
  21. #include "Audit.h"
  22. #include "Definitions.h"
  23.  
  24. #pragma options(pack_enums)
  25. #include <Files.h>
  26. #include <Folders.h>
  27. #include <Finder.h>
  28. #include <Script.h>
  29. #include <Events.h>
  30. #include <Errors.h>
  31. #include <StandardFile.h>
  32. #pragma options(!pack_enums)
  33.  
  34. #include "Files.h"
  35. #include "Memory.h"
  36. #include "Array.h"
  37.  
  38.  
  39. /* open file abstraction.  for efficiency, we ought to be having buffers */
  40. /* and all kinds of stuff in here, but we're too lazy to implement it. */
  41. struct FileType
  42.     {
  43.         /* refnum for Macintosh file system OS calls */
  44.         short                                    Refnum;
  45.     };
  46.  
  47.  
  48. /* global variable containing the last I/O error.  Haven't decided what */
  49. /* to use it for yet. */
  50. static OSErr                            LastError;
  51.  
  52. /* things for debugging */
  53. EXECUTE(static ArrayRec*    FileSpecList;)
  54. EXECUTE(static ArrayRec*    FileDescriptorList;)
  55.  
  56.  
  57. /* initialize the file subsystem.  should only be called from Screen */
  58. MyBoolean                        Eep_InitializeFiles(void)
  59.     {
  60.         APRINT(("+Eep_InitializeFiles"));
  61. #if DEBUG
  62.         FileSpecList = NewArray();
  63.         if (FileSpecList == NIL)
  64.             {
  65.              FailurePoint1:
  66.                 APRINT(("-Eep_InitializeFiles failed"));
  67.                 return False;
  68.             }
  69.         FileDescriptorList = NewArray();
  70.         if (FileDescriptorList == NIL)
  71.             {
  72.              FailurePoint2:
  73.                 DisposeArray(FileSpecList);
  74.                 goto FailurePoint1;
  75.             }
  76. #endif
  77.         APRINT(("-Eep_InitializeFiles"));
  78.         return True;
  79.     }
  80.  
  81.  
  82. /* shutdown the file subsystem. */
  83. void                                Eep_ShutdownFiles(void)
  84.     {
  85.         APRINT(("+Eep_ShutdownFiles"));
  86. #if DEBUG
  87.         ERROR(ArrayGetLength(FileSpecList) != 0,PRERR(AllowResume,
  88.             "Eep_ShutdownFiles:  some file specs still exist"));
  89.         ERROR(ArrayGetLength(FileDescriptorList) != 0,PRERR(AllowResume,
  90.             "FileDescriptorList:  some files are still open"));
  91.         DisposeArray(FileSpecList);
  92.         DisposeArray(FileDescriptorList);
  93. #endif
  94.         APRINT(("-Eep_ShutdownFiles"));
  95.     }
  96.  
  97.  
  98. /* this is an internal routine -- do not use */
  99. #if DEBUG
  100. MyBoolean                        Eep_RegisterFileSpec(FileSpec* Spec)
  101.     {
  102.         CheckPtrExistence(Spec);
  103.         return ArrayAppendElement(FileSpecList,Spec);
  104.     }
  105. #endif
  106.  
  107.  
  108. /* this routine validates a file specification to make sure it exists */
  109. #if DEBUG
  110. void                            ValidateFileSpec(FileSpec* Spec)
  111.     {
  112.         CheckPtrExistence(Spec);
  113.         ERROR(-1 == ArrayFindElement(FileSpecList,Spec),PRERR(ForceAbort,
  114.             "ValidateFileSpec:  undefined file specification"));
  115.     }
  116. #endif
  117.  
  118.  
  119. /* make a copy of a file specification */
  120. /* this routine does not perform operations on file descriptors. */
  121. FileSpec*                        DuplicateFileSpec(FileSpec* Original)
  122.     {
  123.         FileSpec*                    Copy;
  124.  
  125.         APRINT(("+DuplicateFileSpec %xl",Original));
  126.         ERROR(-1 == ArrayFindElement(FileSpecList,Original),PRERR(ForceAbort,
  127.             "DuplicateFileSpec:  undefined file specification"));
  128.         Copy = (FileSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  129.         if (Copy != NIL)
  130.             {
  131.                 CopyData((char*)Original,(char*)Copy,sizeof(FSSpec));
  132.                 if (!Eep_RegisterFileSpec(Copy))
  133.                     {
  134.                         ReleasePtr((char*)Copy);
  135.                         Copy = NIL;
  136.                     }
  137.             }
  138.         APRINT(("-DuplicateFileSpec %xl",Copy));
  139.         return Copy;
  140.     }
  141.  
  142.  
  143. /* dispose of a file specification thing */
  144. void                                DisposeFileSpec(FileSpec* Spec)
  145.     {
  146.         APRINT(("+DisposeFileSpec %xl",Spec));
  147.         ERROR(-1 == ArrayFindElement(FileSpecList,Spec),PRERR(ForceAbort,
  148.             "DisposeFileSpec:  undefined file specification"));
  149.         EXECUTE(ArrayDeleteElement(FileSpecList,ArrayFindElement(FileSpecList,Spec)));
  150.         ReleasePtr((char*)Spec);
  151.         APRINT(("-DisposeFileSpec"));
  152.     }
  153.  
  154.  
  155. /* create a new temporary file with a known unique name, and return a specification */
  156. /* leading to it.  the creator and filetype codes may or may not be used by */
  157. /* the implementation; the Macintosh does use them.  The file is actually created. */
  158. /* this routine does not perform operations on file descriptors. */
  159. FileSpec*                        NewTempFileSpec(unsigned long Creator, unsigned long FileType)
  160.     {
  161.         short                            vRefNum;
  162.         long                            DirID;
  163.         FSSpec*                        Temp;
  164.         unsigned char            Name[32] = "\pTempFile........";
  165.         int                                Scan;
  166.         unsigned long            Key;
  167.  
  168.         APRINT(("+NewTempFileSpec"));
  169.         FindFolder(kOnSystemDisk,kTemporaryFolderType,kCreateFolder,&vRefNum,&DirID);
  170.         Temp = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  171.         if (Temp == NIL)
  172.             {
  173.                 APRINT(("-NewTempFileSpec NIL"));
  174.                 return NIL;
  175.             }
  176.         Key = TickCount();
  177.      TryPoint:
  178.         for (Scan = 0; Scan < 8; Scan += 1)
  179.             {
  180.                 Name[Scan + 9] = ((Key >> (Scan * 4)) & 0x0f) + 'a';
  181.             }
  182.         FSMakeFSSpec(vRefNum,DirID,Name,Temp);
  183.         LastError = FSpCreate(Temp,Creator,FileType,smSystemScript);
  184.         if (LastError == dupFNErr)
  185.             {
  186.                 Key += 1;
  187.                 goto TryPoint;
  188.             }
  189.         if (LastError != noErr)
  190.             {
  191.                 ReleasePtr((char*)Temp);
  192.                 Temp = NIL;
  193.             }
  194.         if (Temp != NIL)
  195.             {
  196.                 if (!Eep_RegisterFileSpec((FileSpec*)Temp))
  197.                     {
  198.                         ReleasePtr((char*)Temp);
  199.                         Temp = NIL;
  200.                     }
  201.             }
  202.         APRINT(("-NewTempFileSpec %r",Temp));
  203.         return (FileSpec*)Temp;
  204.     }
  205.  
  206.  
  207. /* create a file spec leading to a named preference file.  The location of preference */
  208. /* files are implementation defined:  UNIX may put them in the user's home directory */
  209. /* with a leading period; Macintosh puts them in a "Preferences" folder.  The file */
  210. /* is actually created unless it already exists.  PrefsFileName is a null terminated */
  211. /* string. */
  212. /* this routine does not perform operations on file descriptors. */
  213. FileSpec*                        NewPrefsFileSpec(char* PrefsFileName, unsigned long Creator,
  214.                                             unsigned long FileType)
  215.     {
  216.         short                            vRefNum;
  217.         long                            DirID;
  218.         FSSpec*                        Temp;
  219.         unsigned char            Name[32];
  220.         int                                Scan;
  221.  
  222.         APRINT(("+NewPrefsFileSpec name = %t",PrefsFileName));
  223.         FindFolder(kOnSystemDisk,kPreferencesFolderType,kCreateFolder,&vRefNum,&DirID);
  224.         Temp = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  225.         if (Temp == NIL)
  226.             {
  227.                 APRINT(("-NewPrefsFileSpec NIL"));
  228.                 return NIL;
  229.             }
  230.         Scan = 0;
  231.         while ((Scan < 31) && (PrefsFileName[Scan] != 0))
  232.             {
  233.                 Name[Scan + 1] = PrefsFileName[Scan];
  234.                 Scan += 1;
  235.             }
  236.         Name[0] = Scan;
  237.         FSMakeFSSpec(vRefNum,DirID,Name,Temp);
  238.         LastError = FSpCreate(Temp,Creator,FileType,smSystemScript);
  239.         if (!Eep_RegisterFileSpec((FileSpec*)Temp))
  240.             {
  241.                 ReleasePtr((char*)Temp);
  242.                 Temp = NIL;
  243.             }
  244.         APRINT(("-NewPrefsFileSpec %r",Temp));
  245.         return (FileSpec*)Temp;
  246.     }
  247.  
  248.  
  249. /* present a dialog box allowing the user to select where to create a new file. */
  250. /* If the file will overwrite an existing file, verify this with the user and then */
  251. /* delete the existing file before returning. DefaultFileName is a null terminated */
  252. /* string. */
  253. /* this routine does not perform operations on file descriptors. */
  254. FileSpec*                        PutFile(char* DefaultFileName)
  255.     {
  256.         unsigned char            Name[32];
  257.         StandardFileReply    MySFR;
  258.         int                                Scan;
  259.         FSSpec*                        ReturnValue;
  260.  
  261.         APRINT(("+PutFile name = %t",DefaultFileName));
  262.         LastError = noErr;
  263.         Scan = 0;
  264.         while ((Scan < 31) && (DefaultFileName[Scan] != 0))
  265.             {
  266.                 Name[Scan + 1] = DefaultFileName[Scan];
  267.                 Scan += 1;
  268.             }
  269.         Name[0] = Scan;
  270.         StandardPutFile(NIL,Name,&MySFR);
  271.         if (MySFR.sfGood)
  272.             {
  273.                 if (MySFR.sfReplacing)
  274.                     {
  275.                         FSpDelete(&MySFR.sfFile);
  276.                     }
  277.                 ReturnValue = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  278.                 if (ReturnValue == NIL)
  279.                     {
  280.                         APRINT(("-PutFile NIL"));
  281.                         return NIL;
  282.                     }
  283.                 *ReturnValue = MySFR.sfFile;
  284.                 if (MySFR.sfReplacing)
  285.                     {
  286.                         FSpDelete(&MySFR.sfFile);
  287.                     }
  288.             }
  289.          else
  290.             {
  291.                 ReturnValue = NIL;
  292.             }
  293.         if (ReturnValue != NIL)
  294.             {
  295.                 if (!Eep_RegisterFileSpec((FileSpec*)ReturnValue))
  296.                     {
  297.                         ReleasePtr((char*)ReturnValue);
  298.                         ReturnValue = NIL;
  299.                     }
  300.             }
  301.         APRINT(("-PutFile %r",ReturnValue));
  302.         return (FileSpec*)ReturnValue;
  303.     }
  304.  
  305.  
  306. /* let the user find a file with the specified list of types.  Whether the types */
  307. /* are actually used is implementation defined.  The Macintosh uses up to 4 types. */
  308. /* returns NIL if the operation was cancelled. */
  309. /* this routine does not perform operations on file descriptors. */
  310. FileSpec*                        GetFileStandard(long NumFileTypes, unsigned long* ArrayOfFileTypes)
  311.     {
  312.         StandardFileReply    MySFR;
  313.         FSSpec*                        Where;
  314.  
  315.         APRINT(("+GetFileStandard"));
  316.         ERROR((NumFileTypes != 0) && (ArrayOfFileTypes == NIL),PRERR(ForceAbort,
  317.             "GetFileStandard:  file type array is NIL"));
  318.         LastError = noErr;
  319.         StandardGetFile(NIL,NumFileTypes,ArrayOfFileTypes,&MySFR);
  320.         if (MySFR.sfGood)
  321.             {
  322.  
  323.                 Where = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  324.                 if (Where != NIL)
  325.                     {
  326.                         *Where = MySFR.sfFile;
  327.                     }
  328.             }
  329.          else
  330.             {
  331.                 Where = NIL;
  332.             }
  333.         if (Where != NIL)
  334.             {
  335.                 if (!Eep_RegisterFileSpec((FileSpec*)Where))
  336.                     {
  337.                         ReleasePtr((char*)Where);
  338.                         Where = NIL;
  339.                     }
  340.             }
  341.         APRINT(("-GetFileStandard %r",Where));
  342.         return (FileSpec*)Where;
  343.     }
  344.  
  345.  
  346. /* get any file.  like GetFileStandard except it shows all possible files */
  347. /* this routine does not perform operations on file descriptors. */
  348. FileSpec*                        GetFileAny(void)
  349.     {
  350.         StandardFileReply    MySFR;
  351.         FSSpec*                        Where;
  352.  
  353.         APRINT(("+GetFileAny"));
  354.         LastError = noErr;
  355.         StandardGetFile(NIL,-1,NIL,&MySFR);
  356.         if (MySFR.sfGood)
  357.             {
  358.                 Where = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"FileSpec");
  359.                 if (Where != NIL)
  360.                     {
  361.                         *Where = MySFR.sfFile;
  362.                     }
  363.             }
  364.          else
  365.             {
  366.                 Where = NIL;
  367.             }
  368.         if (Where != NIL)
  369.             {
  370.                 if (!Eep_RegisterFileSpec((FileSpec*)Where))
  371.                     {
  372.                         ReleasePtr((char*)Where);
  373.                         Where = NIL;
  374.                     }
  375.             }
  376.         APRINT(("-GetFileAny %r",Where));
  377.         return (FileSpec*)Where;
  378.     }
  379.  
  380.  
  381. /* return a pointer containing a non-null-terminated string which is the filename. */
  382. /* this routine does not perform operations on file descriptors. */
  383. char*                                ExtractFileName(FileSpec* Spec)
  384.     {
  385.         char*                            Name;
  386.  
  387.         CheckPtrExistence(Spec);
  388.         ERROR(-1 == ArrayFindElement(FileSpecList,Spec),PRERR(ForceAbort,
  389.             "ExtractFileName:  undefined file specification"));
  390.         Name = AllocPtrCanFail(((FSSpec*)Spec)->name[0],"ExtractFileName");
  391.         if (Name != NIL)
  392.             {
  393.                 CopyData((char*)&(((FSSpec*)Spec)->name[1]),&(Name[0]),((FSSpec*)Spec)->name[0]);
  394.             }
  395.         return Name;
  396.     }
  397.  
  398.  
  399. /* create a file.  Returns True if the creation succeeded.  Whether or not */
  400. /* the Creator and FileType codes are used is implementation defined.  The Macintosh */
  401. /* does use them. */
  402. /* this routine does not perform operations on file descriptors. */
  403. MyBoolean                        CreateFile(FileSpec* FileLocation, unsigned long Creator,
  404.                                             unsigned long FileType)
  405.     {
  406.         APRINT(("+CreateFile name=%p dir=%l vol=%s",(*(FSSpec*)FileLocation).name,
  407.             (*(FSSpec*)FileLocation).parID,(*(FSSpec*)FileLocation).vRefNum));
  408.         CheckPtrExistence(FileLocation);
  409.         ERROR(-1 == ArrayFindElement(FileSpecList,FileLocation),PRERR(ForceAbort,
  410.             "CreateFile:  undefined file specification"));
  411.         LastError = FSpCreate((FSSpec*)FileLocation,Creator,FileType,smSystemScript);
  412.         APRINT(("-CreateFile err=%s",LastError));
  413.         return (LastError == noErr);
  414.     }
  415.  
  416.  
  417. /* delete a file.  The file must not be in use.  Returns True if successful */
  418. /* this routine does not perform operations on file descriptors. */
  419. MyBoolean                        DeleteFile(FileSpec* FileLocation)
  420.     {
  421.         APRINT(("+DeleteFile"));
  422.         CheckPtrExistence(FileLocation);
  423.         ERROR(-1 == ArrayFindElement(FileSpecList,FileLocation),PRERR(ForceAbort,
  424.             "DeleteFile:  undefined file specification"));
  425.         LastError = FSpDelete((FSSpec*)FileLocation);
  426.         APRINT(("-DeleteFile err=%s",LastError));
  427.         return (LastError == noErr);
  428.     }
  429.  
  430.  
  431. /* Open a file for the specified access.  Returns True if successful. */
  432. /* this routine DOES perform operations on file descriptors. */
  433. MyBoolean                        OpenFile(FileSpec* FileLocation, FileType** FileRefOut,
  434.                                             FileModesType FileAccessMode)
  435.     {
  436.         FileType*                    FileRef;
  437.         int                                Permission;
  438.  
  439.         APRINT(("+OpenFile name=%p dir=%l vol=%s",(*(FSSpec*)FileLocation).name,
  440.             (*(FSSpec*)FileLocation).parID,(*(FSSpec*)FileLocation).vRefNum));
  441.         CheckPtrExistence(FileLocation);
  442.         ERROR(-1 == ArrayFindElement(FileSpecList,FileLocation),PRERR(ForceAbort,
  443.             "OpenFile:  undefined file specification"));
  444.         FileRef = (FileType*)AllocPtrCanFail(sizeof(FileType),"FileType");
  445.         if (FileRef == NIL)
  446.             {
  447.              FailurePoint1:
  448.                 APRINT(("-OpenFile failed"));
  449.                 return False;
  450.             }
  451.         switch (FileAccessMode)
  452.             {
  453.                 default:
  454.                     EXECUTE(PRERR(ForceAbort,"OpenFile:  bad file permission specifier"));
  455.                     break;
  456.                 case eReadOnly:
  457.                     Permission = fsRdPerm;
  458.                     break;
  459.                 case eReadAndWrite:
  460.                     Permission = fsRdWrPerm;
  461.                     break;
  462.             }
  463.         LastError = FSpOpenDF((FSSpec*)FileLocation,Permission,&(FileRef->Refnum));
  464.         if (LastError != noErr)
  465.             {
  466.                 ReleasePtr((char*)FileRef);
  467.                 APRINT((" Error",LastError));
  468.                 goto FailurePoint1;
  469.             }
  470.         EXECUTE(if (!ArrayAppendElement(FileDescriptorList,FileRef))
  471.             {FSClose(FileRef->Refnum); ReleasePtr((char*)FileRef); FileRef = NIL;
  472.             goto FailurePoint1;})
  473.         *FileRefOut = FileRef;
  474.         APRINT(("-OpenFile %r %s",FileRef,FileRef->Refnum));
  475.         return True;
  476.     }
  477.  
  478.  
  479. /* close a file.  The file must have been open.  Implicitly calls FlushLocalBuffers. */
  480. /* this routine DOES perform operations on file descriptors. */
  481. void                                CloseFile(FileType* FileRef)
  482.     {
  483.         APRINT(("+CloseFile %r %s",FileRef,FileRef->Refnum));
  484.         CheckPtrExistence(FileRef);
  485.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  486.             "CloseFile:  undefined file descriptor"));
  487.         FlushLocalBuffers(FileRef);
  488.         LastError = FSClose(FileRef->Refnum);
  489.         EXECUTE(ArrayDeleteElement(FileDescriptorList,
  490.             ArrayFindElement(FileDescriptorList,FileRef)));
  491.         ReleasePtr((char*)FileRef);
  492.         APRINT(("-CloseFile err=%s",LastError));
  493.     }
  494.  
  495.  
  496. /* make sure all data associated with a file gets written out */
  497. /* this routine DOES perform operations on file descriptors. */
  498. void                                FlushLocalBuffers(FileType* FileRef)
  499.     {
  500.         short                            vRefNum;
  501.  
  502.         APRINT(("+FlushLocalBuffers %r %s",FileRef,FileRef->Refnum));
  503.         CheckPtrExistence(FileRef);
  504.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  505.             "FlushLocalBuffers:  undefined file descriptor"));
  506.         LastError = GetVRefNum(FileRef->Refnum,&vRefNum);
  507.         if (LastError == noErr)
  508.             {
  509.                 LastError = FlushVol(NIL,vRefNum);
  510.             }
  511.         APRINT(("-FlushLocalBuffers err=%s",LastError));
  512.     }
  513.  
  514.  
  515. /* write a block of data to the file.  Returns the number of bytes which could */
  516. /* not be written or 0 if all were written. */
  517. /* This is the only function that calls "FSWrite" */
  518. /* this routine DOES perform operations on file descriptors. */
  519. long                                WriteToFile(FileType* FileRef, char* Buffer, long NumBytes)
  520.     {
  521.         APRINT(("+WriteToFile %r %s",FileRef,FileRef->Refnum));
  522.         CheckPtrExistence(FileRef);
  523.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  524.             "WriteToFile:  undefined file descriptor"));
  525.         do
  526.             {
  527.                 long                            NumBytesDone;
  528.  
  529.                 NumBytesDone = NumBytes;
  530.                 LastError = FSWrite(FileRef->Refnum,&NumBytesDone,Buffer);
  531.                 Buffer += NumBytesDone;
  532.                 NumBytes -= NumBytesDone;
  533.                 ERROR(NumBytes != 0,PRERR(AllowResume,
  534.                     "WriteToFile:  couldn't write whole block, trying again"));
  535.             } while ((LastError == noErr) && (NumBytes != 0));
  536.         APRINT(("-WriteToFile err=%s",LastError));
  537.         return NumBytes; /* return number of bytes that couldn't be written */
  538.     }
  539.  
  540.  
  541. /* read a block of data from the file.  Returns the number of bytes which */
  542. /* could not be read, or 0 if all were read. */
  543. /* This is the only function that calls "FSRead" */
  544. /* this routine DOES perform operations on file descriptors. */
  545. long                                ReadFromFile(FileType* FileRef, char* Buffer, long NumBytesDesired)
  546.     {
  547.         EXECUTE(long            TryCount = 0;)
  548.  
  549.         APRINT(("+ReadFromFile %r %s",FileRef,FileRef->Refnum));
  550.         CheckPtrExistence(FileRef);
  551.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  552.             "ReadFromFile:  undefined file descriptor"));
  553.         do
  554.             {
  555.                 long                            NumBytesDone;
  556.  
  557.                 NumBytesDone = NumBytesDesired;
  558.                 LastError = FSRead(FileRef->Refnum,&NumBytesDone,Buffer);
  559.                 Buffer += NumBytesDone;
  560.                 NumBytesDesired -= NumBytesDone;
  561.                 ERROR((NumBytesDesired != 0) && (TryCount > 0),PRERR(AllowResume,
  562.                     "ReadFromFile:  couldn't read whole block, trying again"));
  563.                 EXECUTE(TryCount += 1;)
  564.             } while ((LastError == noErr) && (NumBytesDesired != 0));
  565.         APRINT(("-ReadFromFile err=%s",LastError));
  566.         return NumBytesDesired; /* return number of bytes that couldn't be read */
  567.     }
  568.  
  569.  
  570. /* get the current index into the specified file */
  571. /* this routine DOES perform operations on file descriptors. */
  572. long                                GetFilePosition(FileType* FileRef)
  573.     {
  574.         long                            Where;
  575.  
  576.         APRINT(("+GetFilePosition %r %s",FileRef,FileRef->Refnum));
  577.         CheckPtrExistence(FileRef);
  578.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  579.             "GetFilePosition:  undefined file descriptor"));
  580.         LastError = GetFPos(FileRef->Refnum,&Where);
  581.         APRINT(("-GetFilePosition err=%s",LastError));
  582.         return Where;
  583.     }
  584.  
  585.  
  586. /* move to a new location within the specified file */
  587. /* if the new location is past the EOF, the EOF will be extended to the new location */
  588. /* this routine DOES perform operations on file descriptors. */
  589. MyBoolean                        SetFilePosition(FileType* FileRef, long NewLocation)
  590.     {
  591.         long                            EOF;
  592.  
  593.         APRINT(("+SetFilePosition %r %s",FileRef,FileRef->Refnum));
  594.         CheckPtrExistence(FileRef);
  595.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  596.             "SetFilePosition:  undefined file descriptor"));
  597.         LastError = GetEOF(FileRef->Refnum,&EOF);
  598.         if (EOF < NewLocation)
  599.             {
  600.                 LastError = SetEOF(FileRef->Refnum,NewLocation);
  601.             }
  602.         if (LastError == noErr)
  603.             {
  604.                 LastError = SetFPos(FileRef->Refnum,fsFromStart,NewLocation);
  605.             }
  606.         APRINT(("-SetFilePosition err=%s",LastError));
  607.         return (LastError == noErr);
  608.     }
  609.  
  610.  
  611. /* get the length of the specified file */
  612. /* this routine DOES perform operations on file descriptors. */
  613. long                                GetFileLength(FileType* FileRef)
  614.     {
  615.         long                            EOFPos;
  616.  
  617.         APRINT(("+GetFileLength %r %s",FileRef,FileRef->Refnum));
  618.         CheckPtrExistence(FileRef);
  619.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  620.             "GetFileLength:  undefined file descriptor"));
  621.         LastError = GetEOF(FileRef->Refnum,&EOFPos);
  622.         APRINT(("-GetFileLength err=%s",LastError));
  623.         return EOFPos;
  624.     }
  625.  
  626.  
  627. /* set the length of the specified file. */
  628. /* returns True if everything went well or False if there was an error */
  629. /* If the file could not be extended due to lack of disk space, the EOF */
  630. /* remains unchanged */
  631. /* this routine DOES perform operations on file descriptors. */
  632. MyBoolean                        SetFileLength(FileType* FileRef, long NewFileLength)
  633.     {
  634.         long                            OldEOF;
  635.  
  636.         APRINT(("+SetFileLength %r %s",FileRef,FileRef->Refnum));
  637.         CheckPtrExistence(FileRef);
  638.         ERROR(-1 == ArrayFindElement(FileDescriptorList,FileRef),PRERR(ForceAbort,
  639.             "SetFileLength:  undefined file descriptor"));
  640.         LastError = GetEOF(FileRef->Refnum,&OldEOF);
  641.         if (LastError == noErr)
  642.             {
  643.                 LastError = SetEOF(FileRef->Refnum,NewFileLength);
  644.                 if (LastError == dskFulErr)
  645.                     {
  646.                         SetEOF(FileRef->Refnum,OldEOF);
  647.                     }
  648.             }
  649.         APRINT(("-SetFileLength err=%s",LastError));
  650.         return (LastError == noErr);
  651.     }
  652.  
  653.  
  654. /* copy the entire contents of one file to another.  Data overwrites destination */
  655. /* this routine does not perform operations on file descriptors. */
  656. #define REALBIGBUFFSIZE (65536)
  657. #define LITTLEBUFFSIZE (1024)
  658. MyBoolean                        CopyFile(FileType* Original, FileType* Destination)
  659.     {
  660.         char*                            Buffer;
  661.         MyBoolean                    ReleaseBuffer;
  662.         long                            ActualBufferSize;
  663.         long                            ByteCount;
  664.         char                            EmergencyBuff[LITTLEBUFFSIZE];
  665.  
  666.         CheckPtrExistence(Original);
  667.         CheckPtrExistence(Destination);
  668.         if (!SetFilePosition(Original,0))
  669.             {
  670.                 return False;
  671.             }
  672.         if (!SetFilePosition(Destination,0))
  673.             {
  674.                 return False;
  675.             }
  676.         if (!SetFileLength(Destination,0))
  677.             {
  678.                 return False;
  679.             }
  680.         Buffer = AllocPtrCanFail(REALBIGBUFFSIZE,"CopyFileBuffer");
  681.         if (Buffer != NIL)
  682.             {
  683.                 ActualBufferSize = REALBIGBUFFSIZE;
  684.                 ReleaseBuffer = True;
  685.             }
  686.          else
  687.             {
  688.                 ActualBufferSize = LITTLEBUFFSIZE;
  689.                 ReleaseBuffer = False;
  690.                 Buffer = EmergencyBuff;
  691.             }
  692.         ByteCount = GetFileLength(Original);
  693.         while (ByteCount != 0)
  694.             {
  695.                 long                            LocalBytes;
  696.  
  697.                 if (ByteCount > ActualBufferSize)
  698.                     {
  699.                         LocalBytes = ActualBufferSize;
  700.                     }
  701.                  else
  702.                     {
  703.                         LocalBytes = ByteCount;
  704.                     }
  705.                 if (ReadFromFile(Original,Buffer,LocalBytes) != 0)
  706.                     {
  707.                      FailurePoint:
  708.                         if (ReleaseBuffer)
  709.                             {
  710.                                 ReleasePtr(Buffer);
  711.                             }
  712.                         return False;
  713.                     }
  714.                 if (WriteToFile(Destination,Buffer,LocalBytes) != 0)
  715.                     {
  716.                         goto FailurePoint;
  717.                     }
  718.                 ByteCount -= LocalBytes;
  719.             }
  720.         if (ReleaseBuffer)
  721.             {
  722.                 ReleasePtr(Buffer);
  723.             }
  724.         return True;
  725.     }
  726.  
  727.  
  728. /* create a temporary file in the directory.  the file is actually created so it */
  729. /* exists (so nobody can grab it out from under you). */
  730. /* this routine DOES perform operations on file descriptors. */
  731. FileSpec*                        NewTempFileInTheSameDirectory(FileSpec* SameDirectoryAsThis)
  732.     {
  733.         FSSpec*                        NewOne;
  734.         unsigned char            Name[32] = "\pTempFile........";
  735.         int                                Scan;
  736.         unsigned long            Key;
  737.  
  738.         ERROR(-1 == ArrayFindElement(FileSpecList,SameDirectoryAsThis),PRERR(ForceAbort,
  739.             "DisposeFileSpec:  undefined file specification"));
  740.         CheckPtrExistence(SameDirectoryAsThis);
  741.         NewOne = (FSSpec*)AllocPtrCanFail(sizeof(FSSpec),"SameDirectoryNewName");
  742.         if (NewOne == NIL)
  743.             {
  744.                 return NIL;
  745.             }
  746.         Key = TickCount();
  747.      TryPoint:
  748.         for (Scan = 0; Scan < 8; Scan += 1)
  749.             {
  750.                 Name[Scan + 9] = ((Key >> (Scan * 4)) & 0x0f) + 'a';
  751.             }
  752.         FSMakeFSSpec(((FSSpec*)SameDirectoryAsThis)->vRefNum,
  753.             ((FSSpec*)SameDirectoryAsThis)->parID,Name,NewOne);
  754.         LastError = FSpCreate(NewOne,'\?\?\?\?','\?\?\?\?',smSystemScript);
  755.         if (LastError == dupFNErr)
  756.             {
  757.                 Key += 1;
  758.                 goto TryPoint;
  759.             }
  760.         if (LastError != noErr)
  761.             {
  762.                 /* some other error occurred -- may be a disk full error. */
  763.                 ReleasePtr((char*)NewOne);
  764.                 NewOne = NIL;
  765.             }
  766.         if (NewOne != NIL)
  767.             {
  768.                 if (!Eep_RegisterFileSpec((FileSpec*)NewOne))
  769.                     {
  770.                         ReleasePtr((char*)NewOne);
  771.                         NewOne = NIL;
  772.                     }
  773.             }
  774.         return (FileSpec*)NewOne;
  775.     }
  776.  
  777.  
  778. /* this operation swaps the data forks for two files.  this is used for safe */
  779. /* saving (i.e. write data before clobbering so that the old file still exists */
  780. /* if the write fails).  You create a new file and write the data to it.  Then you */
  781. /* pass the location of the new file in NewFile and the location of the old */
  782. /* file in OldFile.  The routine swaps the data in the files and the last modified */
  783. /* dates.  If successful, the NewFile (temporary file) will be deleted and the */
  784. /* OldFileRef reference will be updated (it will NOT be the same) and the NewFileRef */
  785. /* will be closed. */
  786. /* NOTE:  the files should be created in the same directory. */
  787. /* this routine DOES perform operations on file descriptors. */
  788. MyBoolean                        SwapFileDataForks(FileSpec* NewAndTempFile, FileSpec* OldFile,
  789.                                             FileType* NewFileRef, FileType** OldFileRef)
  790.     {
  791.         ERROR(-1 == ArrayFindElement(FileSpecList,NewAndTempFile),PRERR(ForceAbort,
  792.             "SwapFileDataForks:  undefined file specification"));
  793.         ERROR(-1 == ArrayFindElement(FileSpecList,OldFile),PRERR(ForceAbort,
  794.             "SwapFileDataForks:  undefined file specification"));
  795.         ERROR(-1 == ArrayFindElement(FileDescriptorList,NewFileRef),PRERR(ForceAbort,
  796.             "SwapFileDataForks:  undefined file descriptor"));
  797.         ERROR(-1 == ArrayFindElement(FileDescriptorList,*OldFileRef),PRERR(ForceAbort,
  798.             "SwapFileDataForks:  undefined file descriptor"));
  799.         CheckPtrExistence(NewAndTempFile);
  800.         CheckPtrExistence(OldFile);
  801.         CheckPtrExistence(NewFileRef);
  802.         ERROR(OldFileRef == NIL,PRERR(ForceAbort,"SwapFileDataForks:  OldFileRef is NIL"));
  803.         CheckPtrExistence(*OldFileRef);
  804.         LastError = FSpExchangeFiles((FSSpec*)NewAndTempFile,(FSSpec*)OldFile);
  805.         if (LastError != noErr)
  806.             {
  807.                 return False;
  808.             }
  809.         CloseFile(*OldFileRef);
  810.         *OldFileRef = NewFileRef;
  811.         DeleteFile(NewAndTempFile);
  812.         SetTag(NewAndTempFile,"SwapFileDataForks: NewAndTempFile");
  813.         CheckPtrExistence(*OldFileRef);
  814.         return True;
  815.     }
  816.